TypeScript入门之申明文件

您所在的位置:网站首页 ts 声明文件 TypeScript入门之申明文件

TypeScript入门之申明文件

2023-10-12 12:12| 来源: 网络整理| 查看: 265

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第23天,点击查看活动详情

简介

申明文件在我们平时开发中用到的并不多,但是当我们要开源一个库的时候,就需要我们写申明文件了。

那什么是申明文件?申明文件又有什么作用?以及怎样定义申明文件呢?

什么是申明文件

通常我们会把声明语句放到一个单独的文件(xxx.d.ts)中,这就是声明文件,以 .d.ts 为后缀。

申明文件的作用

虽然 TypeScript 已经逐渐进入主流,但是市面上大部分库还是以 JavaScript 编写的,这个时候由于库没有像 TS 一样定义类型,因此需要一个声明文件来帮助库的使用者来获取库的类型提示。

说到这里小伙伴可能有疑问了,我们学习了接口、类、类型别名不都是用来定义类型的吗?怎么又会出来个申明文件呢?

接口、类、类型别名是用来定义类型别名的。但是每次都需要我们引入然后给变量定义类型。但是申明文件只需要我们申明一次,在项目中不需要再引入和定义类型就能全局直接使用。

我们来看个例子:

我们在new Vue的时候,如果不定义好Vue class是会报错的。并且每次我们new Vue的时候都需要引入class Vue。

// type.js interface VueOption { el: string; data: any; } export class Vue { options: VueOption; constructor(options: VueOption) { this.options = options; } }

使用的时候我们必须import进来。

// main.js import {Vue} from "./type.js" const app = new Vue({ el: "#app", data: { message: "hello world", }, });

我们改造下,使用申明文件

// index.d.ts interface VueOption { el: string; data: any; } declare class Vue { options: VueOption; constructor(options: VueOption); }

有了申明文件,项目全局不需要引入就能直接使用了。

// main.js const app = new Vue({ el: "#app", data: { message: "hello world", }, });

这样就不会报错了。

使用申明文件的好处是我们只需要定义一次就能全局使用。相对接口、类、类型别名来说是更方便的。

发布声明文件

我们为一个开源库编写了声明文件后应该如何发布?

目前有两个选择:

将什么文件向开源库提 PR,声明文件与源码放在一起,作为第一方声明。 发布到 DefinitelyTyped,作为第三方声明文件。 第一方声明

如果是手动写的声明文件,下面三种方式都能被正确的识别:

给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址。

在项目根目录下,编写一个 index.d.ts 文件,该文件会被自动读取。

针对入口文件(package.json 中的 main 字段指定的入口文件),编写一个同名不同后缀的 .d.ts 文件,这样也会被自动读取。

第一种方式是给 package.json 中的 types 或 typings 字段指定一个类型声明文件地址。比如:

{ "name": "foo", "version": "1.0.0", "main": "lib/index.js", "types": "foo.d.ts", }

指定了 types 为 foo.d.ts 之后,导入此库的时候,就会去找 foo.d.ts 作为此库的类型声明文件了。

typings 与 types 一样,只是另一种写法。

如果没有指定 types 或 typings,那么就会在根目录下寻找 index.d.ts 文件,将它视为此库的类型声明文件。

如果没有找到 index.d.ts 文件,那么就会寻找入口文件(package.json 中的 main 字段指定的入口文件)是否存在对应同名不同后缀的 .d.ts 文件。

比如 package.json 是这样时:

{ "name": "foo", "version": "1.0.0", "main": "lib/index.js", }

就会先识别 package.json 中是否存在 types 或 typings 字段。发现不存在,那么就会寻找是否存在 index.d.ts 文件。如果还是不存在,那么就会寻找是否存在 lib/index.d.ts 文件。假如说连 lib/index.d.ts 都不存在的话,就会被认为是一个没有提供类型声明文件的库了。

将声明文件发布到DefinitelyTyped

如果我们是在给别人的仓库添加类型声明文件,但原作者不愿意合并 pull request,那么就需要将声明文件发布到 @types 下。

与普通的 npm 模块不同,@types 是统一由 DefinitelyTyped 管理的。要将声明文件发布到 @types 下,就需要给 DefinitelyTyped 创建一个 pull-request,其中包含了类型声明文件,测试代码,以及 tsconfig.json 等。

pull-request 需要符合它们的规范,并且通过测试,才能被合并,稍后就会被自动发布到 @types 下。

介绍了申明文件的作用以及发布申明文件的两种方法,我们再来说说怎么写申明文件。

写申明文件

前面介绍的DefinitelyTyped,它定义了市面上主流的 JavaScript 库的 d.ts,我们可以在 Type Search里面搜索我们需要的申明文件,然后使用 npm 安装这些 d.ts。

比如我们要安装 JQuery 的 d.ts:

npm install @types/jquery -save

当然,如果使我们自己写的库,需要申明文件,这就需要我们手动来写申明文件了。写申明文件有两种方式。

自动生成

如果库的源码本身就是由 ts 写的,那么在使用 tsc 脚本将 ts 编译为 js 的时候,添加 declaration 选项,就可以同时也生成 .d.ts 声明文件了.

我们可以在命令行中添加 --declaration(简写 -d),或者在 tsconfig.json 中添加 declaration 选项。

这里以 tsconfig.json 为例:

{ "compilerOptions": { "module": "commonjs", "outDir": "lib", "declaration": true, } }

上例中我们添加了 outDir 选项,将 ts 文件的编译结果输出到 lib 目录下,然后添加了 declaration 选项,设置为 true,表示将会由 ts 文件自动生成同名的 .d.ts 声明文件,也会输出到 lib 目录下。

当然如果我们的库是js写的就没办法自动生成了,就只能手写了。

手动写

关键字 declare 表示声明的意思,我们可以用它来做出各种声明:

declare var 声明全局变量 declare function 声明全局方法 declare class 声明全局类 declare enum 声明全局枚举类型 declare namespace 声明(含有子属性的)全局对象 interface 和 type 声明全局类型 声明变量

declare var/let/const,全局变量的声明可以说是最简单的了,虽然 var/let/const 都可以使用的,但是通常情况下全局变量是不允许改动的,大多数情况下还是以 const 为主:

// src/jQuery.d.ts declare const jQuery: (selector: string) => any; 声明函数

declare function 用来声明全局函数:

// src/jQuery.d.ts declare function jQuery(selector: string): any; 声明类

declare class 用于声明全局类

// src/Person.d.ts declare class Person { name: string; constructor(name: string); say(): string; } 声明枚举

declare enum 是于声明全局枚举类型

// src/Directions.d.ts declare enum Directions { Up, Down, Left, Right } 声明命名空间

declare namespace,命名空间虽然在日常开发中已经不常见了,但是在 d.ts 文件编写时还是很常见的,它用来表示全局变量是一个对象,包含很多子属性。

比如 jQuery 是全局对象,而其包含一个 jQuery.ajax 用于处理 ajax 请求,这个时候命名空间就派上用场了:

// src/jQuery.d.ts declare namespace jQuery { function ajax(url: string, settings?: any): void; } 声明interface 和 type

除了全局变量之外,可能有一些类型我们也希望能暴露出来。

在类型声明文件中,我们可以直接使用 interface 或 type 来声明一个全局的接口或类型:

// src/jQuery.d.ts interface AjaxSettings { method?: 'GET' | 'POST' data?: any; } declare namespace jQuery { function ajax(url: string, settings?: AjaxSettings): void; } 声明合并

假如 jQuery 既是一个函数,可以直接被调用 jQuery('#foo'),又是一个对象,拥有子属性 jQuery.ajax()(事实确实如此),那么我们可以组合多个声明语句,它们会不冲突的合并起来:

// src/jQuery.d.ts declare function jQuery(selector: string): any; declare namespace jQuery { function ajax(url: string, settings?: any): void; } // src/index.ts jQuery('#foo'); jQuery.ajax('/api/get_something'); 系列文章

TypeScript入门之环境搭建

TypeScript入门之数据类型

TypeScript入门之函数

TypeScript入门之接口

TypeScript入门之类

TypeScript入门之类型推断、类型断言、双重断言、非空断言、确定赋值断言、类型守卫、类型别名

TypeScript入门之泛型

TypeScript入门之装饰器

TypeScript入门之模块与命名空间

TypeScript入门之申明文件

TypeScript入门之常用内置工具类型

TypeScript入门之配置文件

后记

感谢小伙伴们的耐心观看,本文为笔者个人学习笔记,如有谬误,还请告知,万分感谢!如果本文对你有所帮助,还请点个关注点个赞~,您的支持是笔者不断更新的动力!



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3